package com.xz.xzmybatisagent;

import com.xz.xzmybatisagent.socket.*;
import org.apache.ibatis.plugin.Interceptor;

import java.io.IOException;
import java.net.ServerSocket;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.IntStream;

/**
 * <p>
 * 拦截器使用启用监听
 * </p>
 *
 * @author DONG.WANG17@HAND-CHINA.COM
 * @since 2025/3/20-03-20 19:33
 */
public class ActiveService {
    private static final Map<Integer, ActiveListener> listenerMap = new ConcurrentHashMap<>();

    private ActiveService() {
    }

    public static ActiveListener createListener(int activePort) {
        if (listenerMap.containsKey(activePort)) {
            return listenerMap.get(activePort);
        }
        listenerMap.put(activePort, new ActiveListener(activePort));
        return listenerMap.get(activePort);
    }

    public static ActiveListener createListener(int activePort, boolean active) {
        return listenerMap.computeIfAbsent(activePort, port -> new ActiveListener(port, active));
    }

    public static class ActiveListener {
        private final int activePort;
        private boolean listening = false;
        private volatile Boolean active = true;

        private ActiveListener(int activePort) {
            this.activePort = activePort;
        }

        private ActiveListener(int activePort, boolean active) {
            this.activePort = activePort;
            this.active = active;
        }

        public Boolean getActive() {
            return active;
        }

        public Integer getActivePort() {
            return activePort;
        }

        /**
         * 监听是否激活自定义拦截器
         *
         * @param interceptors 原程序拦截器列表对象
         * @param interceptor  自定义拦截器
         */
        public void listen(List<Interceptor> interceptors, Interceptor interceptor) {
            // 每次调用 listen 都允许添加或移除操作，目的是为了始终将拦截器置于末尾
            if (active) {
                addInterceptor(interceptors, interceptor);
            } else {
                removeInterceptor(interceptors, interceptor);
            }

            // 如果已监听，则阻止继续监听
            if (this.listening) {
                return;
            }
            this.listening = true;

            SocketConfig socketConfig = new SocketConfig(activePort);
            socketConfig.setCallback(new SocketCallback() {
                @Override
                public void onMessage(String message) {
                    if ("ACTIVE:TRUE".equalsIgnoreCase(message)) {
                        active = true;
                        addInterceptor(interceptors, interceptor);
                    } else if ("ACTIVE:FALSE".equalsIgnoreCase(message)) {
                        active = false;
                        removeInterceptor(interceptors, interceptor);
                    }
                }

                @Override
                public void onError(Exception e) {
                    System.err.println("[Sql Sender ActiveListener Server] Error: " + e.getMessage());
                }

                @Override
                public void onStatusChange(ConnectionStatus status) {
                    System.out.println("[Sql Sender ActiveListener Server] Connected status: " + status);
                    if (ConnectionStatus.DISCONNECTED.equals(status)) {
                        System.out.println("[Sql Sender ActiveListener Server] Disconnected.");
                        removeInterceptor(interceptors, interceptor);
                    }
                }
            });
            final SocketEndpoint server = SocketFactory.createServer(socketConfig);
            server.start();
        }

        /**
         * 判断端口是否被占用
         *
         * @param port 待检测端口
         * @return true表示被占用，false表示未被占用
         */
        private boolean isBind(int port) {
            try (ServerSocket socket = new ServerSocket(port)) {
                socket.setReuseAddress(true);
            } catch (IOException e) {
                return true;
            }
            return false;
        }

        private synchronized void addInterceptor(List<Interceptor> interceptors, Interceptor interceptor) {
            try {
                int existingIndex = IntStream.range(0, interceptors.size())
                        .filter(i -> interceptors.get(i).getClass().getName().equals(interceptor.getClass().getName()))
                        .findFirst()
                        .orElse(-1);
                // 创建拦截器实例
                if (existingIndex == -1) {
                    interceptors.add(0, interceptor);
                    System.out.printf("%s added to interceptors.%n", interceptor.getClass().getName());
                } else if (existingIndex != 0) {
                    Collections.swap(interceptors, 0, existingIndex);
                }
            } catch (Throwable t) {
                System.err.printf("Failed to add %s: %s%n", interceptor.getClass().getName(), t.getMessage());
            }
        }

        private synchronized void removeInterceptor(List<Interceptor> interceptors, Interceptor interceptor) {
            try {
                int existingIndex = IntStream.range(0, interceptors.size())
                        .filter(i -> interceptors.get(i).getClass().getName().equals(interceptor.getClass().getName()))
                        .findFirst()
                        .orElse(-1);
                if (existingIndex != -1) {
                    interceptors.remove(existingIndex);
                    System.out.printf("%s removed from interceptors.%n", interceptor.getClass().getName());
                }
            } catch (Throwable t) {
                System.err.printf("Failed to remove %s: %s%n", interceptor.getClass().getName(), t.getMessage());
            }
        }
    }
}
